package com.wdb.modules.security.rest;

import cn.hutool.core.util.IdUtil;
import com.wdb.annotation.rest.AnonymousDeleteMapping;
import com.wdb.annotation.rest.AnonymousGetMapping;
import com.wdb.annotation.rest.AnonymousPostMapping;
import com.wdb.config.RsaProperties;
import com.wdb.exception.BadRequestException;
import com.wdb.modules.security.config.bean.LoginCodeEnum;
import com.wdb.modules.security.config.bean.LoginProperties;
import com.wdb.modules.security.config.bean.SecurityProperties;
import com.wdb.modules.security.dto.AuthUserDto;
import com.wdb.modules.security.security.TokenProvider;
import com.wdb.modules.security.service.OnlineUserService;
import com.wdb.modules.security.service.dto.JwtUserDto;
import com.wdb.utils.RedisUtils;
import com.wdb.utils.RsaUtils;
import com.wdb.utils.SecurityUtils;
import com.wdb.utils.StringUtils;
import com.wf.captcha.base.Captcha;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
@ComponentScan(basePackages = {"com.wdb"})
public class AuthorizationController {
  @Resource SecurityProperties properties;
  @Resource LoginProperties loginProperties;
  private final RedisUtils redisUtils;
  private final AuthenticationManagerBuilder authenticationManagerBuilder;
  private final TokenProvider tokenProvider;
  private final OnlineUserService onlineUserService;

  @ApiOperation("获取验证码")
  @AnonymousGetMapping("/code")
  public ResponseEntity<Object> getCode() {
    // 获取验证码
    Captcha captcha = loginProperties.getCaptcha();
    // 生成uuid;
    String uuid = properties.getCodeKey() + IdUtil.simpleUUID();
    System.out.println(properties);
    // 验证码结果
    // 当验证码类型为 arithmetic时且长度 >= 2 时，captcha.text()的结果有几率为浮点型
    String captchaValue = captcha.text();
    if (captcha.getCharType() - 1 == LoginCodeEnum.ARITHMETIC.ordinal()
        && captchaValue.contains(".")) {
      captchaValue = captchaValue.split("\\.")[0];
    }
    // 存入Redis
    boolean redisSetRes =
        redisUtils.set(
            uuid, captchaValue, loginProperties.getLoginCode().getExpiration(), TimeUnit.MINUTES);
    // 返回验证码信息
    HashMap<String, Object> imgRest = new HashMap<>(2);
    imgRest.put("img", captcha.toBase64());
    imgRest.put("uuid", uuid);
    return ResponseEntity.ok(imgRest);
  }

  @AnonymousPostMapping("/login")
  public ResponseEntity<Object> login(
      @Validated @RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception {
    System.out.println("/login");
    String password =
        RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, authUser.getPassword());
    // 获取验证码
    String code = (String) redisUtils.get(authUser.getUuid());
    // 清除验证码
    // redisUtils.del(authUser.getUuid());
    // 验证码是否存在
    if (StringUtils.isBlank(code)) {
      throw new BadRequestException("验证码不存在或已过期");
    }
    // 验证码错误
    if (StringUtils.isBlank(authUser.getCode()) || !authUser.getCode().equals(code)) {
      log.info(authUser.getCode() + "--" + code);
      throw new BadRequestException("验证码错误");
    }
    // 生成 jwt token
    UsernamePasswordAuthenticationToken authenticationToken =
        new UsernamePasswordAuthenticationToken(authUser.getUsername(), password);
    Authentication authentication =
        authenticationManagerBuilder.getObject().authenticate(authenticationToken);
    SecurityContextHolder.getContext().setAuthentication(authentication);
    // 生成令牌与第三方系统获取令牌方式
    // UserDetails userDetails = userDetailsService.loadUserByUsername(userInfo.getUsername());
    // Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null,
    // userDetails.getAuthorities());
    // SecurityContextHolder.getContext().setAuthentication(authentication);
    // 创建token
    String token = tokenProvider.createToken(authentication);
    JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal();
    HashMap<String, Object> authInfo = new HashMap<>(2);
    authInfo.put("token", properties.getTokenStartWith() + token);
    authInfo.put("user", jwtUserDto);
    log.info("3333{}", authInfo);
    if (loginProperties.isSingleLogin()) {
      // 踢掉之前已经登录的token
      onlineUserService.kickOutForUsername(authUser.getUsername());
    }
    // 保存在线信息
    onlineUserService.save(jwtUserDto, token, request);
    return ResponseEntity.ok(authInfo);
  }

  @ApiOperation("获取登录的用户信息")
  @GetMapping("/info")
  public ResponseEntity<UserDetails> getUserInfo() {
    return ResponseEntity.ok(SecurityUtils.getCurrentUser());
  }

  @ApiOperation("退出登录")
  @AnonymousDeleteMapping(value = "/logout")
  public ResponseEntity<Object> logout(HttpServletRequest request) {
    // token
    String token = tokenProvider.getToken(request);

    return new ResponseEntity<>(HttpStatus.OK);
  }
}
